import axios from "axios";
import md5 from 'blueimp-md5';
import { ElMessage } from "element-plus";
import config from "~/config";


// 返回true表示需要签名，false表示不需要签名
function checkNeedSign(key,path) {
  const NOAUTH_TOKENS_USER = ['token','user_id'];
 if (path.endsWith('index') && NOAUTH_TOKENS_USER.includes(key)) {
  // 1. 在首页的情况下，token、user_id不需要签名
   return false;
 } else if(path.endsWith('loginOut') && key === 'token') {
  // 2. 注销登录的情况下,token需要签名
  return true;
 } else if(path.endsWith('selApplyList') && key === 'user_id') {
  // 3. 渠道申请审批情况下，user_id不需要签名
  return false;
 } else if(key === 'token') {
   // 4. 其他情况下,token不需要签名
  return false;
 }
 return true;
}


const RequestError = function (response) {
  Error.apply(this, [response.return_msg]);
  return {
    response,
  };
};
RequestError.prototype = new Error();

class Request {
  _instance;

  #baseURL;

  #timeout = 30000;

  #dataType = "json";

  #signKey = "SMOZY";

  constructor(config) {
    this.#baseURL = config.baseURL;
    const timeout = Number(config.timeout);
    if (!isNaN(timeout) && timeout > 0) {
      this.#timeout = config.timeout;
    }

    if (config.dataType) {
      this.#dataType = config.dataType;
    }
  }

  static getInstance(config) {
    if (!this._instance) {
      this._instance = new this(config);
    }
    return this._instance;
  }

  upload(routeObj, config) {
    const formData = new FormData();
    formData.append("files", config.file);
    formData.append("name", config.name);
    formData.append("filePath", config.filePath);
    return axios.request({
      url: this.#url(routeObj),
      method: "post",
      headers: {
        "Content-Type": "multipart/form-data",
      },
      data: formData,
      timeout: this.#timeout,
    });
  }

  request(path, method, data) {
    const signedData = this.#sign(data,path);
    return axios
      .request({
        url:this.#url(path),
        method,
        timeout: this.#timeout,
        data: method !== "GET" ? this.#dataToUrlEncoded(signedData) : {},
        params: method === "GET" ? signedData : {},
        responseType: this.#dataType,
      })
      .then((response) => {
        if (response.data.return_code && response.data.return_code == 2000) {
          return response.data;
        } else {
          const err = new RequestError(response.data);
          // this.#handleError(err);
          return Promise.reject(err);
        }
      })
      .catch((err) => {
        // if (!this.#shouldExcept(routeObj)) {
        //   this.#handleError(err);
        // }
        this.#handleError(err);
        return Promise.reject(err);
      });
  }
  requestnolanguage(routeObj, method, data) {
    const signedData = this.#signnolanguage(data);
    return axios
      .request({
        url: this.#url(routeObj),
        method,
        timeout: this.#timeout,
        data: method !== "GET" ? this.#dataToUrlEncoded(signedData) : {},
        params: method === "GET" ? signedData : {},
        responseType: this.#dataType,
      })
      .then((response) => {
        if (response.data.return_code && response.data.return_code == 20030) {
          return response.data;
        } else {
          const err = new RequestError(response.data);
          this.#handleError(err);
          return Promise.reject(err);
        }
      })
      .catch((err) => {
        if (!this.#shouldExcept(routeObj)) {
          this.#handleError(err);
        }
        this.#handleError(err);
        return Promise.reject(err);
      });
  }

  #shouldExcept(routeObj) {
    const methods = ["getVserison"];
    return methods.indexOf(routeObj.m) > -1;
  }

  #handleError(err) {
    // if (
    //   (err.response && err.response.return_code == 5800) ||
    //   err.response.return_code == 51222 ||
    //   err.response.return_code == 51333
    // ) {
    //   return;
    // }
    // const { t } = i18n.global;
    // let message = t("app.request-error");
    // if (err.response && err.response.return_msg) {
    //   message = err.response.return_msg;
    // }
    // clog("handleError:", err);
    ElMessage.error(err.response.return_msg);
  }

  get(path, params) {
    return this.request(path, "GET", params);
  }

  post(path, body) {
    return this.request(path, "POST", body);
  }

  postnolanguage(path, body, auth) {
    return this.requestnolanguage(path, "POST", body);
  }

  // #url({ action, m, module = "api" }) {
  //   return `${this.#baseURL}?module=${module}&action=${action}&m=${m}`;
  // }
 
  #url(path) {
    return `${this.#baseURL}${path}`;
  }

  #sign(data,path) {
    const timestamp = Math.floor(new Date().getTime() / 1000);
    const body = Object.assign(
      {
        language_type: this.#languageType(),
        timestamp,
      },
      data
    );
    let queries = [];
    Object.keys(body).forEach((key) => {
      checkNeedSign(key,path) && queries.push(`${key}=${body[key]}`);
    });

    queries.sort(function (item1, item2) {
      return item1 > item2 ? 1 : item1 === item2 ? 0 : -1;
    });
    // clog("sign:", `${queries.join("&")}&signKey=${this.#signKey}`)
    const signStr = md5(`${queries.join("&")}&signKey=${this.#signKey}`);
    body.sign = signStr;
    return body;
  }

  #signnolanguage(data) {
    const timestamp = Math.floor(new Date().getTime() / 1000);
    const body = Object.assign(
      {
        timestamp,
      },
      data
    );
    let queries = [];
    for (let key in body) {
      queries.push(`${key}=${body[key]}`);
    }
    queries.sort(function (item1, item2) {
      return item1 > item2 ? 1 : item1 === item2 ? 0 : -1;
    });
    const signStr = md5(`${queries.join("&")}&signKey=${this.#signKey}`);
    body.sign = signStr;
    return body;
  }

  #languageType() {
    return 1; // 1:繁体 2:英语
  }
   /**
    * 对象转换成key=value&key=value形式的字符串
    */
  #dataToUrlEncoded(dataObj) {
    let dataStr = "";
    for (let key in dataObj) {
      dataStr += key + "=" + dataObj[key] + "&";
    }
    return dataStr.substring(0, dataStr.length - 1);
  }
}

const baseURL = config[import.meta.env.MODE].baseUrl;

const instance = Request.getInstance({
  baseURL,
});
export default instance;
